// LeftView.cpp : implementation of the CLeftView class
//

#include "stdafx.h"
#include "SpriteTool.h"

#include "SpriteDoc.h"
#include "LeftView.h"
#include "ChildFrm.h"
#include "SpriteView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CLeftView

IMPLEMENT_DYNCREATE(CLeftView, CTreeView)

BEGIN_MESSAGE_MAP(CLeftView, CTreeView)
	//{{AFX_MSG_MAP(CLeftView)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChanged)
	ON_COMMAND(ID_MAKE_DN, OnMakeDn)
	ON_COMMAND(ID_MAKE_UP, OnMakeUp)
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnBeginLabelEdit)
	ON_COMMAND(ID_AUTO_PLAY, OnAutoPlay)
	ON_UPDATE_COMMAND_UI(ID_AUTO_PLAY, OnUpdateAutoPlay)
	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit)
	ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
	ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
	ON_COMMAND(ID_EDIT_CUT, OnEditCut)
	ON_COMMAND(ID_DELETE, OnDelete)
	ON_COMMAND(ID_NEW_ACTION, OnNewAction)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLeftView construction/destruction

CLeftView::CLeftView()
{
	m_nTimer = 0;
	m_bPlay = TRUE;

	m_hCutItem = NULL;
	m_hCopyItem = NULL;

	m_hActFrame = NULL;
}

CLeftView::~CLeftView()
{
}

BOOL CLeftView::PreCreateWindow(CREATESTRUCT& cs)
{
	return CTreeView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CLeftView drawing

void CLeftView::OnDraw(CDC* pDC)
{
	CSpriteDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
}


void CLeftView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	CTreeCtrl& tree = GetTreeCtrl();

	tree.ModifyStyle(0, TVS_HASBUTTONS|TVS_SHOWSELALWAYS|TVS_EDITLABELS);

	HTREEITEM hRoot = tree.GetRootItem();

	CSpriteDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	list<SPRITE*>::iterator it;
	it = pDoc->m_Sprites.begin();
	while(it != pDoc->m_Sprites.end())
	{
		SPRITE* pSprite = *it++;

		HTREEITEM hSprite = tree.InsertItem(pSprite->szName, hRoot);
		tree.SetItemData(hSprite, (DWORD)pSprite);

		list<ACTION*>::iterator ait;
		ait = pSprite->ActionList.begin();
		while(ait != pSprite->ActionList.end())
		{
			ACTION* pAction = *ait++;

			HTREEITEM hAction = tree.InsertItem(pAction->szName, hSprite);
			tree.SetItemData(hAction, (DWORD)pAction);

			list<FRAME*>::iterator fit;
			fit = pAction->FrameList.begin();
			while(fit != pAction->FrameList.end())
			{
				FRAME* pFrame = *fit++;

				HTREEITEM hFrame = tree.InsertItem(pFrame->szName, hAction);
				tree.SetItemData(hFrame, (DWORD)pFrame);

				list<FCLIP*>::iterator cit;
				cit = pFrame->FclipList.begin();
				while(cit != pFrame->FclipList.end())
				{
					FCLIP* pFclip = *cit++;

					HTREEITEM hFclip = tree.InsertItem(pFclip->szName, hFrame);
					tree.SetItemData(hFclip, (DWORD)pFclip);
				}
			}
		}
		tree.Expand(hSprite, TVE_EXPAND);
	}
	m_hCutItem = NULL;
	m_hCopyItem = NULL;
	m_hActFrame = NULL;
}

/////////////////////////////////////////////////////////////////////////////
// CLeftView diagnostics

#ifdef _DEBUG
void CLeftView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CLeftView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CSpriteDoc* CLeftView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSpriteDoc)));
	return (CSpriteDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CLeftView message handlers

void CLeftView::OnNewFrame() 
{
	HTREEITEM hAction = GetActionItem(NULL);
	if(hAction)
	{
		CTreeCtrl& tree = GetTreeCtrl();

		ACTION* pAction = (ACTION*)tree.GetItemData(hAction);
		if(pAction && pAction->nType == CSpriteDoc::tAction)
		{
			FRAME* pFrame = pAction->AddFrame(_T("frame"));

			HTREEITEM hFrame = tree.InsertItem(pFrame->szName, hAction);
			tree.SetItemData(hFrame, (DWORD)pFrame);

			tree.SelectItem(hFrame);
			OnSelect(hFrame);
		}
	}	
}

void CLeftView::OnNewAction() 
{
	HTREEITEM hSprite = GetSpriteItem(NULL);
	if(hSprite)
	{
		CTreeCtrl& tree = GetTreeCtrl();

		SPRITE* pSprite = (SPRITE*)tree.GetItemData(hSprite);
		if(pSprite && pSprite->nType == CSpriteDoc::tSprite)
		{
			ACTION* pAction = pSprite->AddAction(_T("NewAction"));
			if(pAction)
			{
				FRAME* pFrame = pAction->AddFrame(_T("frame"));

				HTREEITEM hAction = tree.InsertItem(pAction->szName, hSprite);
				tree.SetItemData(hAction, (DWORD)pAction);

				HTREEITEM hFrame = tree.InsertItem(pFrame->szName, hAction);
				tree.SetItemData(hFrame, (DWORD)pFrame);

				tree.SelectItem(hFrame);
				OnSelect(hFrame);
			}
		}
	}	
}


void CLeftView::OnNewSprite() 
{
	CTreeCtrl& tree = GetTreeCtrl();

	CSpriteDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	SPRITE* pSprite = pDoc->NewSprite(_T("NewSprite"));
	if(pSprite)
	{
		ACTION* pAction = pSprite->AddAction(_T("NewAction"));
		if(pAction)
		{
			FRAME* pFrame = pAction->AddFrame(_T("frame"));

			HTREEITEM hSprite = tree.InsertItem(pSprite->szName, NULL);
			tree.SetItemData(hSprite, (DWORD)pSprite);

			HTREEITEM hAction = tree.InsertItem(pAction->szName, hSprite);
			tree.SetItemData(hAction, (DWORD)pAction);

			HTREEITEM hFrame = tree.InsertItem(pFrame->szName, hAction);
			tree.SetItemData(hFrame, (DWORD)pFrame);

			tree.SelectItem(hFrame);
			OnSelect(hFrame);
		}
	}
}

void CLeftView::OnSelChanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	HTREEITEM hSelect = pNMTreeView->itemNew.hItem;

	OnSelect(hSelect);
	
	*pResult = 0;
}

void CLeftView::OnSelect(HTREEITEM hSelect)
{
	CSpriteDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	
	BOOL bUpdate = FALSE;
	
	if(hSelect)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			switch(pData->nType)
			{
			case CSpriteDoc::tSprite:
				{
					SPRITE* pSprite = (SPRITE*)pData;
					if(pDoc->m_pSelSprite != pSprite)
					{
						pDoc->m_pSelSprite = pSprite;
						pDoc->m_pSelAction = NULL;
						pDoc->m_pSelFrame = NULL;
						pDoc->m_pSelFclip = NULL;

						if(pSprite->ActionList.size() > 0)
						{
							HTREEITEM hAction = tree.GetChildItem(hSelect);
							ACTION* pAction = (ACTION*)tree.GetItemData(hAction);
							if(pAction)
							{
								pDoc->m_pSelAction = pAction;
							}
						}
						
						bUpdate = TRUE;
					}
				}
				break;
			case CSpriteDoc::tAction:
				{
					ACTION* pAction = (ACTION*)pData;
					if(pDoc->m_pSelAction != pAction)
					{
						pDoc->m_pSelAction = pAction;
						pDoc->m_pSelFrame = NULL;

						if(pAction->FrameList.size() > 0)
						{
							HTREEITEM hFrame = tree.GetChildItem(hSelect);
							FRAME* pFrame = (FRAME*)tree.GetItemData(hFrame);
							if(pFrame)
							{
								pDoc->m_pSelFrame = pFrame;
							}
						}
						
						pDoc->m_pSelFclip = NULL;
						bUpdate = TRUE;

						if(m_hActFrame)
						{
							m_hActFrame = NULL;
							KillTimer(m_nTimer);
							m_nTimer = 0;
						}
					}

					if(m_hActFrame == NULL && m_bPlay)
					{
						if(pAction->FrameList.size() > 1)
						{
							m_hActFrame = tree.GetChildItem(hSelect);
							FRAME* pFrame = (FRAME*)tree.GetItemData(m_hActFrame);
							if(pFrame)
							{
								pDoc->m_pSelFrame = pFrame;
								if(pFrame->nDelay <= 0)
								{
									m_nTimer = SetTimer(100, 100, NULL);
								}
								else
								{
									m_nTimer = SetTimer(100, pFrame->nDelay, NULL);
								}
							}
						}

					}
				}
				break;

			case CSpriteDoc::tFrame:
				{
					if(m_hActFrame)
					{
						KillTimer(m_nTimer);
						m_nTimer = 0;
						m_hActFrame = NULL;
					}

					HTREEITEM hAction = tree.GetParentItem(hSelect);
					if(hAction)
					{
						TDATA* pActionData = (TDATA*)tree.GetItemData(hAction);
						if(pActionData)
						{
							ACTION* pAction = (ACTION*)pActionData;
							FRAME* pFrame = (FRAME*)pData;
							if(pAction != pDoc->m_pSelAction)
							{
								pDoc->m_pSelAction = pAction;
								pDoc->m_pSelFrame = pFrame;
								pDoc->m_pSelFclip = NULL;
								bUpdate = TRUE;
							}
							else if(pFrame != pDoc->m_pSelFrame)
							{
								pDoc->m_pSelFrame = pFrame;
								pDoc->m_pSelFclip = NULL;
								bUpdate = TRUE;
							}
						}
					}
				}
				break;
			case CSpriteDoc::tFclip:
				{
					if(m_hActFrame)
					{
						KillTimer(m_nTimer);
						m_nTimer = 0;
						m_hActFrame = NULL;
					}

					HTREEITEM hFrame = tree.GetParentItem(hSelect);
					if(hFrame)
					{
						TDATA* pFrameData = (TDATA*)tree.GetItemData(hFrame);

						HTREEITEM hSprite = tree.GetParentItem(hFrame);
						if(hSprite)
						{
							TDATA* pSpriteData = (TDATA*)tree.GetItemData(hSprite);
							if(pSpriteData && pFrameData)
							{
								SPRITE* pSprite = (SPRITE*)pSpriteData;
								FRAME* pFrame = (FRAME*)pFrameData;
								FCLIP* pFclip = (FCLIP*)pData;
								
								if(pSprite != pDoc->m_pSelSprite)
								{
									pDoc->m_pSelSprite = pSprite;
									pDoc->m_pSelFrame = pFrame;
									pDoc->m_pSelFclip = NULL;
									bUpdate = TRUE;
								}
								else if(pFrame != pDoc->m_pSelFrame)
								{
									pDoc->m_pSelFrame = pFrame;
									pDoc->m_pSelFclip = NULL;
									bUpdate = TRUE;
								}
								else
								{
									pDoc->m_pSelFclip = pFclip;
									bUpdate = TRUE;
								}
							}

						}
					}
				}
				break;
			}
		}
	}
	if(bUpdate)
	{
		CChildFrame* pFrameWnd = (CChildFrame*)GetParentFrame();
		if(pFrameWnd)
		{
			CSpriteView* pSpriteView = pFrameWnd->GetSpriteView();
			if(pSpriteView)
			{
				pSpriteView->Invalidate();
			}
		}
	}	
}

void CLeftView::HitSelect(int x, int y)
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			HTREEITEM hFrame = NULL;
			switch(pData->nType)
			{
			case CSpriteDoc::tFrame:
				hFrame = hSelect;
				break;
			case CSpriteDoc::tFclip:
				hFrame = tree.GetParentItem(hSelect);
				break;
			}
			if(hFrame)
			{
				CPoint pt(x, y);

				HTREEITEM hFclip = tree.GetChildItem(hFrame);
				while(hFclip)
				{
					HTREEITEM hNext = tree.GetNextSiblingItem(hFclip);
					if(hNext != NULL)
					{
						hFclip = hNext;
					}
					else break;
				}
				while(hFclip)
				{
					FCLIP* pFclip = (FCLIP*)tree.GetItemData(hFclip);
					if(pFclip && pFclip->pImage)
					{
						RECT rect;
						pFclip->GetRect(rect);

						if(PtInRect(&rect, pt))
						{
							tree.Select(hFclip, TVGN_CARET);
							OnSelect(hFclip);
							break;
						}
					}
					hFclip = tree.GetPrevSiblingItem(hFclip);
				}
				
			}
		}
	}
}

HTREEITEM CLeftView::GetSpriteItem(HTREEITEM hSelect)
{
	HTREEITEM hSprite = NULL;
	CTreeCtrl& tree = GetTreeCtrl();
	if(hSelect == NULL)
		hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			switch(pData->nType)
			{
			case CSpriteDoc::tSprite:
				hSprite = hSelect;
				break;
			case CSpriteDoc::tAction:
				hSprite = tree.GetParentItem(hSelect);
				break;
			case CSpriteDoc::tFrame:
				{
					HTREEITEM hAction = tree.GetParentItem(hSelect);
					hSprite = tree.GetParentItem(hAction);
				}
				break;
			case CSpriteDoc::tFclip:
				{
					HTREEITEM hFrame = tree.GetParentItem(hSelect);
					HTREEITEM hAction = tree.GetParentItem(hFrame);
					hSprite = tree.GetParentItem(hAction);
				}
				break;
			}
		}
	}
	return hSprite;
}


HTREEITEM CLeftView::GetActionItem(HTREEITEM hSelect)
{
	HTREEITEM hAction = NULL;
	CTreeCtrl& tree = GetTreeCtrl();
	if(hSelect == NULL)
		hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			switch(pData->nType)
			{
			case CSpriteDoc::tSprite:
				hAction = tree.GetChildItem(hSelect);
				break;
			case CSpriteDoc::tAction:
				hAction = hSelect;
				break;
			case CSpriteDoc::tFrame:
				hAction = tree.GetParentItem(hSelect);
				break;
			case CSpriteDoc::tFclip:
				{
					HTREEITEM hFrame = tree.GetParentItem(hSelect);
					hAction = tree.GetParentItem(hFrame);
				}
				break;
			}
		}
	}
	return hAction;
}


HTREEITEM CLeftView::GetFrameItem(HTREEITEM hSelect)
{
	HTREEITEM hFrame = NULL;
	CTreeCtrl& tree = GetTreeCtrl();
	if(hSelect == NULL)
		hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			switch(pData->nType)
			{
			case CSpriteDoc::tSprite:
				{
					HTREEITEM hAction = tree.GetChildItem(hSelect);
					if(hAction)
					{
						hFrame = tree.GetChildItem(hAction);
					}
				}
				break;
			case CSpriteDoc::tAction:
				hFrame = tree.GetChildItem(hSelect);
				break;

			case CSpriteDoc::tFrame:
				hFrame = hSelect;
				break;
			case CSpriteDoc::tFclip:
				hFrame = tree.GetParentItem(hSelect);
				break;
			}
		}
	}
	return hFrame;
}

HTREEITEM CLeftView::GetFclipItem(HTREEITEM hSelect)
{
	HTREEITEM hFclip = NULL;
	CTreeCtrl& tree = GetTreeCtrl();
	if(hSelect == NULL)
		hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			switch(pData->nType)
			{
			case CSpriteDoc::tSprite:
				{
					HTREEITEM hAction = tree.GetChildItem(hSelect);
					if(hAction)
					{
						HTREEITEM hFrame = tree.GetChildItem(hAction);
						if(hFrame)
						{
							hFclip = tree.GetChildItem(hFrame);
						}
					}
				}
				break;
			case CSpriteDoc::tAction:
				{
					HTREEITEM hFrame = tree.GetChildItem(hSelect);
					if(hFrame)
					{
						hFclip = tree.GetChildItem(hFrame);
					}
				}
				break;
			case CSpriteDoc::tFrame:
				hFclip = tree.GetChildItem(hSelect);
				break;

			case CSpriteDoc::tFclip:
				hFclip = hSelect;
				break;
			}
		}
	}
	return hFclip;
}

void CLeftView::OnAddFclip(LPCTSTR p)
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hFrame = GetFrameItem(NULL);
	if(hFrame)
	{
		FRAME* pFrame = (FRAME*)tree.GetItemData(hFrame);
		FCLIP* pFclip = pFrame->AddFclip(p);
		if(pFclip != NULL)
		{
			CSpriteDoc* pDoc = GetDocument();
			pDoc->LinkImage(pFclip);

			HTREEITEM hFclip = tree.InsertItem(pFclip->szName, hFrame);
			tree.SetItemData(hFclip, (DWORD)pFclip);
			
			tree.Select(hFclip, TVGN_CARET);
			OnSelect(hFclip);

		}
	}
}

HTREEITEM CLeftView::GetSelectFclip()
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData->nType == CSpriteDoc::tFclip)
		{
			return hSelect;
		}
	}
	return NULL;
}

template <class TYPE> bool SwapList(list<TYPE*>& refList, TYPE* v1, TYPE* v2)
{
	list<TYPE*>::iterator it, fit1, fit2;
	fit1 = fit2 = refList.end();
	it = refList.begin();
	while(it != refList.end())
	{
		TYPE* pv = *it;
		if(pv == v1)
		{
			fit1 = it;
			if(fit2 != refList.end())
				break;
		}
		else if(pv == v2)
		{
			fit2 = it;
			if(fit1 != refList.end())
				break;
		}
		it++;
	}
	if(fit1 != refList.end() && fit2 != refList.end())
	{
		*fit1 = v2;
		*fit2 = v1;
		return true;
	}
	return false;
}

void CLeftView::SwapFclip(HTREEITEM hFclip1, HTREEITEM hFclip2)
{
	CTreeCtrl& tree = GetTreeCtrl();
	FCLIP* pFclip1 = (FCLIP*)tree.GetItemData(hFclip1);
	FCLIP* pFclip2 = (FCLIP*)tree.GetItemData(hFclip2);

	HTREEITEM hFrame1 = tree.GetParentItem(hFclip1);
	HTREEITEM hFrame2 = tree.GetParentItem(hFclip2);

	if(hFrame1 == hFrame2)
	{
		FRAME* pFrame = (FRAME*)tree.GetItemData(hFrame1);
		if(pFrame && pFrame->nType == CSpriteDoc::tFrame)
		{
			if(SwapList<FCLIP>(pFrame->FclipList, pFclip1, pFclip2))
			{
				tree.SetItemData(hFclip1, (DWORD)pFclip2);
				tree.SetItemData(hFclip2, (DWORD)pFclip1);

				CString szText1 = tree.GetItemText(hFclip1);
				CString szText2 = tree.GetItemText(hFclip2);

				tree.SetItemText(hFclip1, szText2);
				tree.SetItemText(hFclip2, szText1);
			}
		}
	}
}

void CLeftView::OnSetFclipDn()
{
	HTREEITEM hFclip = GetSelectFclip();
	if(hFclip)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		HTREEITEM hFnext = tree.GetNextSiblingItem(hFclip);
		if(hFnext != NULL)
		{
			SwapFclip(hFclip, hFnext);
			tree.Select(hFnext, TVGN_CARET);
			OnSelect(hFnext);
		}
	}
}

void CLeftView::OnSetFclipUp()
{
	HTREEITEM hFclip = GetSelectFclip();
	if(hFclip)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		HTREEITEM hFprev = tree.GetPrevSiblingItem(hFclip);
		if(hFprev != NULL)
		{
			SwapFclip(hFclip, hFprev);
			tree.Select(hFprev, TVGN_CARET);
			OnSelect(hFprev);
		}
	}
}

void CLeftView::OnMakeDn() 
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		switch(pData->nType)
		{
		case CSpriteDoc::tSprite:
			break;
		case CSpriteDoc::tAction:
			break;
		case CSpriteDoc::tFrame:
			OnMoveFrame(hSelect, -1);
			break;
		case CSpriteDoc::tFclip:
			OnSetFclipDn();	
			break;
		default:
			break;
		}
	}	
}

void CLeftView::OnMakeUp() 
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		switch(pData->nType)
		{
		case CSpriteDoc::tSprite:
			break;
		case CSpriteDoc::tAction:
			break;
		case CSpriteDoc::tFrame:
			OnMoveFrame(hSelect, 1);
			break;
		case CSpriteDoc::tFclip:
			OnSetFclipUp();	
			break;
		default:
			break;
		}
	}
}

void CLeftView::OnMoveFrame(HTREEITEM& hFrame, int nMove)
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hAction = tree.GetParentItem(hFrame);

	ACTION* pAction = (ACTION*)tree.GetItemData(hAction);
	if(pAction && pAction->nType == CSpriteDoc::tAction)
	{
		HTREEITEM hAfter = NULL;
		if(nMove >= 0) // up
		{
			HTREEITEM hPrev = tree.GetPrevSiblingItem(hFrame);
			if(hPrev)
			{
				hAfter = tree.GetPrevSiblingItem(hPrev);
				if(hAfter == NULL)
					hAfter = TVI_FIRST;
			}
		}
		else if(nMove < 0) // down
		{
			hAfter = tree.GetNextSiblingItem(hFrame);
		}
		if(hAfter != NULL)
		{
			HTREEITEM hTar = tree.InsertItem("", hAction, hAfter);
			CloneFrame(hFrame, hTar);
			tree.DeleteItem(hFrame);
			hFrame = hTar;

			tree.SelectItem(hFrame);
			OnSelect(hFrame);

			pAction->FrameList.clear();

			HTREEITEM hChild = tree.GetChildItem(hAction);
			while(hChild)
			{
				FRAME* pFrame = (FRAME*)tree.GetItemData(hChild);
				pAction->FrameList.push_back(pFrame);
				hChild = tree.GetNextSiblingItem(hChild);
			}
		}

	}

}

void CLeftView::CloneFrame(HTREEITEM hSrc, HTREEITEM hTar)
{
	if(hSrc != hTar)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		
		if(tree.ItemHasChildren(hTar))
		{
			HTREEITEM hChild = tree.GetChildItem(hTar);
			while(hChild)
			{
				tree.DeleteItem(hChild);
				hChild = tree.GetChildItem(hTar);
			}
		}
		tree.SetItemText(hTar, tree.GetItemText(hSrc));
		tree.SetItemData(hTar, tree.GetItemData(hSrc));

		HTREEITEM hChild = tree.GetChildItem(hSrc);
		while(hChild)
		{
			HTREEITEM hItem = tree.InsertItem(tree.GetItemText(hChild), hTar);
			tree.SetItemData(hItem, tree.GetItemData(hChild));
			hChild = tree.GetNextSiblingItem(hChild);
		}
	}
}

void CLeftView::CopySprite(HTREEITEM hSrc, HTREEITEM hTar)
{
	if(hSrc != hTar)
	{
		CTreeCtrl& tree = GetTreeCtrl();

		SPRITE* pSrc = (SPRITE*)tree.GetItemData(hSrc);

		CString szSprite = pSrc->GetSprite();

		SPRITE* pSprite = GetDocument()->NewSprite(szSprite);
		tree.SetItemData(hTar, (DWORD)pSprite);

		HTREEITEM hChild = tree.GetChildItem(hSrc);
		while(hChild)
		{
			HTREEITEM hItem = tree.InsertItem(tree.GetItemText(hChild), hTar);
			CopyAction(hChild, hItem);

			hChild = tree.GetNextSiblingItem(hChild);
		}
	}
}


void CLeftView::CopyAction(HTREEITEM hSrc, HTREEITEM hTar)
{
	if(hSrc != hTar)
	{
		CTreeCtrl& tree = GetTreeCtrl();

		ACTION* pSrc = (ACTION*)tree.GetItemData(hSrc);
		
		CString szAction = pSrc->GetAction();
		
		HTREEITEM hSprite = tree.GetParentItem(hTar);
		SPRITE* pSprite = (SPRITE*)tree.GetItemData(hSprite);

		ACTION* pAction = pSprite->AddAction(szAction);
		if(pAction)
		{
			CString szText = tree.GetItemText(hSrc);
			tree.SetItemText(hTar, szText);
			tree.SetItemData(hTar, (DWORD)pAction);

			if(tree.ItemHasChildren(hTar))
			{
				HTREEITEM hChild = tree.GetChildItem(hTar);
				while(hChild)
				{
					if(tree.ItemHasChildren(hChild))
					{
						HTREEITEM hChild2 = tree.GetChildItem(hChild);
						while(hChild2)
						{
							tree.DeleteItem(hChild2);
							hChild2 = tree.GetChildItem(hChild);
						}
					}
					tree.DeleteItem(hChild);
					hChild = tree.GetChildItem(hTar);
				}
			}

			HTREEITEM hChild = tree.GetChildItem(hSrc);
			while(hChild)
			{
				HTREEITEM hItem = tree.InsertItem(tree.GetItemText(hChild), hTar);
				CopyFrame(hChild, hItem);

				hChild = tree.GetNextSiblingItem(hChild);
			}


		}
	}
}

void CLeftView::CopyFrame(HTREEITEM hSrc, HTREEITEM hTar)
{
	if(hSrc != hTar)
	{
		CTreeCtrl& tree = GetTreeCtrl();

		FRAME* pSrc = (FRAME*)tree.GetItemData(hSrc);
		
		CString szFrame = pSrc->GetFrame();
		
		HTREEITEM hAction = tree.GetParentItem(hTar);
		ACTION* pAction = (ACTION*)tree.GetItemData(hAction);

		FRAME* pFrame = pAction->AddFrame(szFrame);
		if(pFrame)
		{
			CString szText = tree.GetItemText(hSrc);
			tree.SetItemText(hTar, szText);
			tree.SetItemData(hTar, (DWORD)pFrame);

			if(tree.ItemHasChildren(hTar))
			{
				HTREEITEM hChild = tree.GetChildItem(hTar);
				while(hChild)
				{
					tree.DeleteItem(hChild);
					hChild = tree.GetChildItem(hTar);
				}
			}

			CSpriteDoc* pDoc = GetDocument();

			HTREEITEM hChild = tree.GetChildItem(hSrc);
			while(hChild)
			{
				CString szText = tree.GetItemText(hChild);

				FCLIP* pSrc = (FCLIP*)tree.GetItemData(hChild);

				CString szFclip = pSrc->GetFclip();

				FCLIP* pFclip = pFrame->AddFclip(szFclip);
				pDoc->LinkImage(pFclip);

				HTREEITEM hItem = tree.InsertItem(szText, hTar);
				tree.SetItemData(hItem, (DWORD)pFclip);

				hChild = tree.GetNextSiblingItem(hChild);
			}

		}
	}
}

void CLeftView::CopyFclip(HTREEITEM hSrc, HTREEITEM hTar)
{
	if(hSrc != hTar)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		
		FCLIP* pSrc = (FCLIP*)tree.GetItemData(hSrc);
		CString szFclip = pSrc->GetFclip();

		CString szText = tree.GetItemText(hSrc);
		tree.SetItemText(hTar, szText);

		HTREEITEM hFrame = tree.GetParentItem(hTar);
		FRAME* pFrame = (FRAME*)tree.GetItemData(hFrame);
		if(pFrame && pFrame->nType == CSpriteDoc::tFrame)
		{
			FCLIP* pFclip = pFrame->AddFclip(szFclip);
			if(pFclip)
			{
				GetDocument()->LinkImage(pFclip);

				tree.SetItemData(hTar, (DWORD)pFclip);
			}
		}
	}
}

void CLeftView::OnTimer(UINT nIDEvent) 
{
	CTreeView::OnTimer(nIDEvent);
	if(m_hActFrame)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		HTREEITEM hNext = tree.GetNextSiblingItem(m_hActFrame);
		if(hNext)
		{
			m_hActFrame = hNext;
		}
		else
		{
			HTREEITEM hSprite = tree.GetParentItem(m_hActFrame);
			m_hActFrame = tree.GetChildItem(hSprite);
		}
		FRAME* pFrame = (FRAME*)tree.GetItemData(m_hActFrame);
		if(pFrame)
		{
			CSpriteDoc* pDoc = GetDocument();
			ASSERT_VALID(pDoc);

			pDoc->m_pSelFrame = pFrame;
			CChildFrame* pFrameWnd = (CChildFrame*)GetParentFrame();
			if(pFrameWnd)
			{
				CSpriteView* pSpriteView = pFrameWnd->GetSpriteView();
				if(pSpriteView)
				{
					pSpriteView->Invalidate();
				}
			}
			KillTimer(m_nTimer);
			if(pFrame->nDelay <= 0)
			{
				m_nTimer = SetTimer(100, 100, NULL);
			}
			else
			{
				m_nTimer = SetTimer(100, pFrame->nDelay, NULL);
			}
		}
	}
	
	
}

void CLeftView::OnDestroy() 
{
	if(m_nTimer)
	{
		KillTimer(m_nTimer);
		m_nTimer = 0;
	}
	CTreeView::OnDestroy();
}

void CLeftView::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
	
	*pResult = 0;
}

void CLeftView::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
	
	CString szNew = pTVDispInfo->item.pszText;
	HTREEITEM hItem = pTVDispInfo->item.hItem;
	if(hItem && !szNew.IsEmpty())
	{

		CTreeCtrl& tree = GetTreeCtrl();
		TDATA* pData = (TDATA*)tree.GetItemData(hItem);
		if(pData)
		{
			if(pData->nType == CSpriteDoc::tSprite)
			{
				SPRITE* pSprite = (SPRITE*)pData;
				pSprite->szName = szNew;
			}
			else if(pData->nType == CSpriteDoc::tAction)
			{
				ACTION* pAction = (ACTION*)pData;
				pAction->szName = szNew;
			}
			else if(pData->nType == CSpriteDoc::tFrame)
			{
				FRAME* pFrame = (FRAME*)pData;
				pFrame->szName = szNew;
				pFrame->ApplyDelay(false);

			}
			tree.SetItemText(hItem, szNew);
		}
	}
	
	*pResult = 0;
}

void CLeftView::OnAutoPlay() 
{
	m_bPlay = !m_bPlay;
	if(m_bPlay == FALSE)
	{
		if(m_hActFrame)
		{
			KillTimer(m_nTimer);
			m_nTimer = 0;
			m_hActFrame = NULL;
		}
	}
	else
	{
		CTreeCtrl& tree = GetTreeCtrl();
		HTREEITEM hSelect = tree.GetSelectedItem();
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData && pData->nType == CSpriteDoc::tAction)
		{
			ACTION* pAction = (ACTION*)pData;

			if(m_hActFrame == NULL)
			{
				if(pAction->FrameList.size() > 1)
				{
					m_hActFrame = tree.GetChildItem(hSelect);
					FRAME* pFrame = (FRAME*)tree.GetItemData(m_hActFrame);
					if(pFrame)
					{
						CSpriteDoc* pDoc = GetDocument();
						pDoc->m_pSelFrame = pFrame;
						if(pFrame->nDelay <= 0)
						{
							m_nTimer = SetTimer(100, 100, NULL);
						}
						else
						{
							m_nTimer = SetTimer(100, pFrame->nDelay, NULL);
						}
					}
				}

			}
		}
	}
}

void CLeftView::OnUpdateAutoPlay(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bPlay);
}


void CLeftView::OnEditCut() 
{
	CTreeCtrl& tree = GetTreeCtrl();
	m_hCutItem = tree.GetSelectedItem();
	m_hCopyItem = NULL;
}

void CLeftView::OnEditCopy() 
{
	CTreeCtrl& tree = GetTreeCtrl();
	m_hCopyItem = tree.GetSelectedItem();
	m_hCutItem = NULL;
}

void CLeftView::OnEditPaste() 
{
	HTREEITEM hCopyItem = m_hCopyItem != NULL ? m_hCopyItem : m_hCutItem;
	if(hCopyItem == NULL)
		return;

	CTreeCtrl& tree = GetTreeCtrl();
	TDATA* pData = (TDATA*)tree.GetItemData(hCopyItem);
	if(pData)
	{
		switch(pData->nType)
		{
		case CSpriteDoc::tSprite:
			{
				HTREEITEM hAfter = GetSpriteItem(NULL);
				if(hAfter == NULL)
					hAfter = TVI_LAST;
				
				int nNameId = 0;
				CString szName;
				CString szFormat = tree.GetItemText(hCopyItem);
				szFormat += _T(" %d");
				szName.Format(szFormat, nNameId++);
				
				HTREEITEM hRoot = NULL;
				
				BOOL bOverlap;
				do
				{
					bOverlap = FALSE;
					HTREEITEM hChild = tree.GetChildItem(hRoot);
					while(hChild)
					{
						CString szText = tree.GetItemText(hChild);
						if(szText == szName)
						{
							szName.Format(szFormat, nNameId++);
							bOverlap = TRUE;
							break;
						}
						hChild = tree.GetNextSiblingItem(hChild);
					}
				}while(bOverlap);
				
				
				HTREEITEM hNewSprite = tree.InsertItem(szName, hRoot, hAfter);
				CopySprite(hCopyItem, hNewSprite);
				
				tree.SelectItem(hNewSprite);
				OnSelect(hNewSprite);

				if(m_hCutItem)
				{
					DeleteSprite(m_hCutItem);
					m_hCutItem = NULL;
				}
			}
			break;
		case CSpriteDoc::tAction:
			{
				HTREEITEM hSprite = GetSpriteItem(NULL);
				if(hSprite)
				{
					HTREEITEM hAfter = GetActionItem(NULL);
					if(hAfter == NULL)
						hAfter = TVI_LAST;
					
					HTREEITEM hNewAction = tree.InsertItem(_T("action"), hSprite, hAfter);
					CopyAction(hCopyItem, hNewAction);
					
					tree.SelectItem(hNewAction);
					OnSelect(hNewAction);

					if(m_hCutItem)
					{
						DeleteAction(m_hCutItem);
						m_hCutItem = NULL;
					}
				}
			}
			break;
		case CSpriteDoc::tFrame:
			{
				HTREEITEM hAction = GetActionItem(NULL);
				if(hAction)
				{
					HTREEITEM hAfter = GetFrameItem(NULL);
					if(hAfter == NULL)
						hAfter = TVI_LAST;
					
					HTREEITEM hNewFrame = tree.InsertItem(_T("frame"), hAction, hAfter);
					CopyFrame(hCopyItem, hNewFrame);
					
					tree.SelectItem(hNewFrame);
					OnSelect(hNewFrame);

					if(m_hCutItem)
					{
						DeleteFrame(m_hCutItem);
						m_hCutItem = NULL;
					}
				}
			}
			break;
		case CSpriteDoc::tFclip:
			{
				HTREEITEM hFrame = GetFrameItem(NULL);
				if(hFrame)
				{
					HTREEITEM hAfter = GetFclipItem(NULL);
					if(hAfter == NULL)
						hAfter = TVI_LAST;
					HTREEITEM hNewFclip = tree.InsertItem(_T("fclip"), hFrame, hAfter);
					CopyFclip(hCopyItem, hNewFclip);
					
					tree.SelectItem(hNewFclip);
					OnSelect(hNewFclip);

					if(m_hCutItem)
					{
						DeleteFclip(m_hCutItem);
						m_hCutItem = NULL;
					}
				}
			}
			break;
		}
	}
}


BOOL CLeftView::DeleteFclip(HTREEITEM hFclip)
{
	CTreeCtrl& tree = GetTreeCtrl();
	TDATA* pData = (TDATA*)tree.GetItemData(hFclip);
	if(pData && pData->nType == CSpriteDoc::tFclip)
	{
		HTREEITEM hFrame = tree.GetParentItem(hFclip);
		if(hFrame)
		{
			FRAME* pFrame = (FRAME*)tree.GetItemData(hFrame);
			if(pFrame && pFrame->nType == CSpriteDoc::tFrame)
			{
				if(tree.DeleteItem(hFclip))
				{
					pFrame->DelFclip((FCLIP*)pData);
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

BOOL CLeftView::DeleteFrame(HTREEITEM hFrame)
{
	CTreeCtrl& tree = GetTreeCtrl();
	TDATA* pData = (TDATA*)tree.GetItemData(hFrame);
	if(pData && pData->nType == CSpriteDoc::tFrame)
	{
		HTREEITEM hAction = tree.GetParentItem(hFrame);
		if(hAction)
		{
			ACTION* pAction = (ACTION*)tree.GetItemData(hAction);
			if(pAction && pAction->nType == CSpriteDoc::tAction)
			{
				if(tree.DeleteItem(hFrame))
				{
					FRAME* pFrame = (FRAME*)pData;
					pAction->DelFrame(pFrame);
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}


BOOL CLeftView::DeleteAction(HTREEITEM hFrame)
{
	CTreeCtrl& tree = GetTreeCtrl();
	TDATA* pData = (TDATA*)tree.GetItemData(hFrame);
	if(pData && pData->nType == CSpriteDoc::tFrame)
	{
		HTREEITEM hSprite = tree.GetParentItem(hFrame);
		if(hSprite)
		{
			SPRITE* pSprite = (SPRITE*)tree.GetItemData(hSprite);
			if(pSprite && pSprite->nType == CSpriteDoc::tSprite)
			{
				if(tree.DeleteItem(hFrame))
				{
					ACTION* pAction = (ACTION*)pData;
					pSprite->DelAction(pAction);
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

BOOL CLeftView::DeleteSprite(HTREEITEM hSprite)
{
	CTreeCtrl& tree = GetTreeCtrl();
	TDATA* pData = (TDATA*)tree.GetItemData(hSprite);
	if(pData && pData->nType == CSpriteDoc::tSprite)
	{
		if(tree.DeleteItem(hSprite))
		{
			SPRITE* pSprite = (SPRITE*)pData;
			GetDocument()->DelSprite(pSprite);
			return TRUE;
		}
	}
	return FALSE;
}

void CLeftView::OnDelete() 
{
	CTreeCtrl& tree = GetTreeCtrl();
	HTREEITEM hSelect = tree.GetSelectedItem();
	if(hSelect)
	{
		TDATA* pData = (TDATA*)tree.GetItemData(hSelect);
		if(pData)
		{
			switch(pData->nType)
			{
			case CSpriteDoc::tSprite:
				m_bDeleteSuccess = DeleteSprite(hSelect);
				break;
			case CSpriteDoc::tAction:
				m_bDeleteSuccess = DeleteAction(hSelect);
				break;
			case CSpriteDoc::tFrame:
				m_bDeleteSuccess = DeleteFrame(hSelect);
				break;
			case CSpriteDoc::tFclip:
				m_bDeleteSuccess = DeleteFclip(hSelect);
				break;
			}
		}
	}
	m_bDeleteSuccess = FALSE;
}
